/**
 ******************************************************************************
 * @file           : bsp_gpio.c
 * @brief          : GPIO Driver Implementation (STM32H7xx)
 ******************************************************************************
 * @attention
 *
 * GPIO驱动程序实现文件
 * 提供简化的GPIO操作接口
 * 支持GPIOA~GPIOK
 *
 ******************************************************************************
 */

/* Includes ------------------------------------------------------------------*/
#include "./BSP/GPIO/bsp_gpio.h"
#include "./BSP/GPIO/bsp_gpio_config.h"

/* Private includes ----------------------------------------------------------*/
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
static GPIO_Error_e gpio_clock_enable(GPIO_TypeDef *GPIOx);
static uint32_t gpio_mode_to_hal(GPIO_Mode_e mode);
static uint32_t gpio_pull_to_hal(GPIO_Pull_e pull);
static uint32_t gpio_speed_to_hal(GPIO_Speed_e speed);

/* Private functions ---------------------------------------------------------*/

/**
 * @brief       使能GPIO时钟
 *
 * @param[in]   GPIOx GPIO端口
 *
 * @retval      GPIO_OK         成功
 * @retval      GPIO_ERROR_INVALID_PORT 无效的端口
 */
static GPIO_Error_e gpio_clock_enable(GPIO_TypeDef *GPIOx)
{
    if (GPIOx == GPIOA)
        __HAL_RCC_GPIOA_CLK_ENABLE();
    else if (GPIOx == GPIOB)
        __HAL_RCC_GPIOB_CLK_ENABLE();
    else if (GPIOx == GPIOC)
        __HAL_RCC_GPIOC_CLK_ENABLE();
    else if (GPIOx == GPIOD)
        __HAL_RCC_GPIOD_CLK_ENABLE();
    else if (GPIOx == GPIOE)
        __HAL_RCC_GPIOE_CLK_ENABLE();
    else if (GPIOx == GPIOF)
        __HAL_RCC_GPIOF_CLK_ENABLE();
    else if (GPIOx == GPIOG)
        __HAL_RCC_GPIOG_CLK_ENABLE();
    else if (GPIOx == GPIOH)
        __HAL_RCC_GPIOH_CLK_ENABLE();
    else if (GPIOx == GPIOI)
        __HAL_RCC_GPIOI_CLK_ENABLE();
    else if (GPIOx == GPIOJ)
        __HAL_RCC_GPIOJ_CLK_ENABLE();
    else if (GPIOx == GPIOK)
        __HAL_RCC_GPIOK_CLK_ENABLE();
    else
    {
        log_e("无效的GPIO端口: 0x%08X", (uint32_t)GPIOx);
        return GPIO_ERROR_INVALID_PORT;
    }
    
    return GPIO_OK;
}

/**
 * @brief       GPIO模式转换为HAL库模式
 *
 * @param[in]   mode GPIO_Mode_e枚举
 *
 * @retval      uint32_t HAL库模式
 */
static uint32_t gpio_mode_to_hal(GPIO_Mode_e mode)
{
    switch (mode)
    {
        case GPIO_MODE_INPUT:
            return GPIO_MODE_INPUT;
        case GPIO_MODE_OUTPUT_PP:
            return GPIO_MODE_OUTPUT_PP;
        case GPIO_MODE_OUTPUT_OD:
            return GPIO_MODE_OUTPUT_OD;
        case GPIO_MODE_AF_PP:
            return GPIO_MODE_AF_PP;
        case GPIO_MODE_AF_OD:
            return GPIO_MODE_AF_OD;
        case GPIO_MODE_ANALOG:
            return GPIO_MODE_ANALOG;
        default:
            return GPIO_MODE_INPUT;
    }
}

/**
 * @brief       GPIO上下拉转换为HAL库模式
 *
 * @param[in]   pull GPIO_Pull_e枚举
 *
 * @retval      uint32_t HAL库上下拉模式
 */
static uint32_t gpio_pull_to_hal(GPIO_Pull_e pull)
{
    switch (pull)
    {
        case GPIO_NOPULL:
            return GPIO_NOPULL;
        case GPIO_PULLUP:
            return GPIO_PULLUP;
        case GPIO_PULLDOWN:
            return GPIO_PULLDOWN;
        default:
            return GPIO_NOPULL;
    }
}

/**
 * @brief       GPIO速度转换为HAL库速度
 *
 * @param[in]   speed GPIO_Speed_e枚举
 *
 * @retval      uint32_t HAL库速度
 */
static uint32_t gpio_speed_to_hal(GPIO_Speed_e speed)
{
    switch (speed)
    {
        case GPIO_SPEED_LOW:
            return GPIO_SPEED_FREQ_LOW;
        case GPIO_SPEED_MEDIUM:
            return GPIO_SPEED_FREQ_MEDIUM;
        case GPIO_SPEED_HIGH:
            return GPIO_SPEED_FREQ_HIGH;
        default:
            return GPIO_SPEED_FREQ_LOW;
    }
}

/* Exported functions --------------------------------------------------------*/

/**
 * @brief       GPIO初始化引脚
 *
 * @param[in]   GPIOx GPIO端口（GPIOA~GPIOK）
 * @param[in]   GPIO_Pin GPIO引脚（GPIO_PIN_0~GPIO_PIN_15）
 * @param[in]   mode GPIO模式
 * @param[in]   pull GPIO上下拉
 * @param[in]   speed GPIO速度
 *
 * @retval      GPIO_OK 成功
 * @retval      GPIO_ERROR_PARAM 参数错误
 * @retval      GPIO_ERROR_INVALID_PORT 无效的端口
 *
 * @note        初始化GPIO引脚配置
 */
GPIO_Error_e gpio_init_pin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin, GPIO_Mode_e mode, GPIO_Pull_e pull, GPIO_Speed_e speed)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    GPIO_Error_e ret;
    
    /* 参数检查 */
    if (GPIOx == NULL || GPIO_Pin == 0)
    {
        log_w("GPIO初始化参数错误: GPIOx=%p, GPIO_Pin=0x%04X", GPIOx, GPIO_Pin);
        return GPIO_ERROR_PARAM;
    }
    
    /* 使能GPIO时钟 */
    ret = gpio_clock_enable(GPIOx);
    if (ret != GPIO_OK)
    {
        return ret;
    }
    
    /* 配置GPIO */
    GPIO_InitStruct.Pin = GPIO_Pin;
    GPIO_InitStruct.Mode = gpio_mode_to_hal(mode);
    GPIO_InitStruct.Pull = gpio_pull_to_hal(pull);
    GPIO_InitStruct.Speed = gpio_speed_to_hal(speed);
    
    HAL_GPIO_Init(GPIOx, &GPIO_InitStruct);
    
    log_d("GPIO初始化完成 Port=0x%08X Pin=0x%04X", (uint32_t)GPIOx, GPIO_Pin);
    return GPIO_OK;
}

/**
 * @brief       写GPIO引脚电平
 *
 * @param[in]   GPIOx GPIO端口
 * @param[in]   GPIO_Pin GPIO引脚
 * @param[in]   level 电平（GPIO_PIN_LOW/GPIO_PIN_HIGH）
 *
 * @retval      GPIO_OK 成功
 * @retval      GPIO_ERROR_PARAM 参数错误
 *
 * @note        阻塞写操作
 */
GPIO_Error_e gpio_write_pin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin, GPIO_PinLevel_e level)
{
    if (GPIOx == NULL || GPIO_Pin == 0)
    {
        log_w("GPIO写参数错误: GPIOx=%p, GPIO_Pin=0x%04X", GPIOx, GPIO_Pin);
        return GPIO_ERROR_PARAM;
    }
    
    HAL_GPIO_WritePin(GPIOx, GPIO_Pin, (GPIO_PinState)level);
    log_d("GPIO写成功: Port=0x%08X Pin=0x%04X Level=%d", (uint32_t)GPIOx, GPIO_Pin, level);
    return GPIO_OK;
}

/**
 * @brief       读GPIO引脚电平
 *
 * @param[in]   GPIOx GPIO端口
 * @param[in]   GPIO_Pin GPIO引脚
 * @param[out]  level 电平指针
 *
 * @retval      GPIO_OK 成功
 * @retval      GPIO_ERROR_PARAM 参数错误
 *
 * @note        非阻塞读操作
 */
GPIO_Error_e gpio_read_pin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin, GPIO_PinLevel_e *level)
{
    if (GPIOx == NULL || GPIO_Pin == 0 || level == NULL)
    {
        log_w("GPIO读参数错误: GPIOx=%p, GPIO_Pin=0x%04X, level=%p", GPIOx, GPIO_Pin, level);
        return GPIO_ERROR_PARAM;
    }
    
    *level = (GPIO_PinLevel_e)HAL_GPIO_ReadPin(GPIOx, GPIO_Pin);
    log_d("GPIO读成功: Port=0x%08X Pin=0x%04X Level=%d", (uint32_t)GPIOx, GPIO_Pin, *level);
    return GPIO_OK;
}

/**
 * @brief       翻转GPIO引脚电平
 *
 * @param[in]   GPIOx GPIO端口
 * @param[in]   GPIO_Pin GPIO引脚
 *
 * @retval      GPIO_OK 成功
 * @retval      GPIO_ERROR_PARAM 参数错误
 *
 * @note        翻转电平
 */
GPIO_Error_e gpio_toggle_pin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
{
    if (GPIOx == NULL || GPIO_Pin == 0)
    {
        log_w("GPIO翻转参数错误: GPIOx=%p, GPIO_Pin=0x%04X", GPIOx, GPIO_Pin);
        return GPIO_ERROR_PARAM;
    }
    
    HAL_GPIO_TogglePin(GPIOx, GPIO_Pin);
    log_d("GPIO翻转成功: Port=0x%08X Pin=0x%04X", (uint32_t)GPIOx, GPIO_Pin);
    return GPIO_OK;
}

/**
 * @brief       写GPIO端口值
 *
 * @param[in]   GPIOx GPIO端口
 * @param[in]   value 16位端口值
 *
 * @retval      GPIO_OK 成功
 * @retval      GPIO_ERROR_PARAM 参数错误
 *
 * @note        写整个端口
 */
GPIO_Error_e gpio_write_port(GPIO_TypeDef *GPIOx, uint16_t value)
{
    if (GPIOx == NULL)
    {
        log_w("GPIO端口写参数错误: GPIOx=%p", GPIOx);
        return GPIO_ERROR_PARAM;
    }
    
    GPIOx->ODR = value;
    log_d("GPIO端口写成功: Port=0x%08X Value=0x%04X", (uint32_t)GPIOx, value);
    return GPIO_OK;
}

/**
 * @brief       读GPIO端口值
 *
 * @param[in]   GPIOx GPIO端口
 * @param[out]  value 端口值指针
 *
 * @retval      GPIO_OK 成功
 * @retval      GPIO_ERROR_PARAM 参数错误
 *
 * @note        读整个端口
 */
GPIO_Error_e gpio_read_port(GPIO_TypeDef *GPIOx, uint16_t *value)
{
    if (GPIOx == NULL || value == NULL)
    {
        log_w("GPIO端口读参数错误: GPIOx=%p, value=%p", GPIOx, value);
        return GPIO_ERROR_PARAM;
    }
    
    *value = (uint16_t)GPIOx->IDR;
    log_d("GPIO端口读成功: Port=0x%08X Value=0x%04X", (uint32_t)GPIOx, *value);
    return GPIO_OK;
}

/**
 * @brief       锁定GPIO引脚配置
 *
 * @param[in]   GPIOx GPIO端口
 * @param[in]   GPIO_Pin GPIO引脚
 *
 * @retval      GPIO_OK 成功
 * @retval      GPIO_ERROR_PARAM 参数错误
 *
 * @note        锁定后，直到下次复位前无法修改引脚配置
 */
GPIO_Error_e gpio_lock_pin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
{
    if (GPIOx == NULL || GPIO_Pin == 0)
    {
        log_w("GPIO锁定参数错误: GPIOx=%p, GPIO_Pin=0x%04X", GPIOx, GPIO_Pin);
        return GPIO_ERROR_PARAM;
    }
    
    HAL_GPIO_LockPin(GPIOx, GPIO_Pin);
    log_w("GPIO引脚已锁定 Port=0x%08X Pin=0x%04X", (uint32_t)GPIOx, GPIO_Pin);
    return GPIO_OK;
}

/**
 * @brief       打印GPIO当前状态（用于调试）
 *
 * @param[in]   GPIOx GPIO端口
 * @param[in]   GPIO_Pin GPIO引脚
 *
 * @retval      无
 *
 * @note        显示引脚电平等信息
 */
void gpio_print_status(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
{
    GPIO_PinLevel_e level;
    
    if (GPIOx == NULL || GPIO_Pin == 0)
    {
        log_e("GPIO状态参数错误");
        return;
    }
    
    if (gpio_read_pin(GPIOx, GPIO_Pin, &level) == GPIO_OK)
    {
        log_i("GPIO引脚状态: Port=0x%08X Pin=0x%04X Level=%s", (uint32_t)GPIOx, GPIO_Pin, level ? "HIGH" : "LOW");
    }
}
